﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Karno8
{
    class Karno
    {
        private byte Count;
        private byte tedad; // tedad anasor natije
        private struct kcell
        {
            public byte value;
            public Boolean tag;
        }
        private kcell[,] karno;
        private string[] result;

        private bool getCell(byte index) // get value of cell by an index
        {
            switch (index)
            {
                case 0: { if (karno[1, 1].value == 1) return true;  else return false;  }
                case 1: { if (karno[2, 1].value == 1) return true;  else return false;  }
                case 2: { if (karno[1, 2].value == 1) return true;  else return false;  }
                case 3: { if (karno[2, 2].value == 1) return true;  else return false;  }
                case 4: { if (karno[1, 4].value == 1) return true;  else return false;  }
                case 5: { if (karno[2, 4].value == 1) return true;  else return false;  }
                case 6: { if (karno[1, 3].value == 1) return true;  else return false;  }
                case 7: { if (karno[2, 3].value == 1) return true;  else return false;  }
            }
            return false;
        }
        private bool getCellTag(byte index) // get tag of cell by an index
        {
            switch (index)
            {
                case 0: return karno[1, 1].tag;
                case 1: return karno[2, 1].tag;
                case 2: return karno[1, 2].tag;
                case 3: return karno[2, 2].tag;
                case 4: return karno[1, 4].tag;
                case 5: return karno[2, 4].tag;
                case 6: return karno[1, 3].tag;
                case 7: return karno[2, 3].tag;
            }
            return false;
        }
        private void setCell(byte index, byte val)
        {
            switch (index)
            {
                case 0: { karno[1, 1].value = val; if (val == 1) karno[1, 1].tag = true; else karno[1, 1].tag = false; } break;
                case 1: { karno[2, 1].value = val; if (val == 1) karno[2, 1].tag = true; else karno[2, 1].tag = false; } break;
                case 2: { karno[1, 2].value = val; if (val == 1) karno[1, 2].tag = true; else karno[1, 2].tag = false; } break;
                case 3: { karno[2, 2].value = val; if (val == 1) karno[2, 2].tag = true; else karno[2, 2].tag = false; } break;
                case 4: { karno[1, 4].value = val; if (val == 1) karno[1, 4].tag = true; else karno[1, 4].tag = false; } break;
                case 5: { karno[2, 4].value = val; if (val == 1) karno[2, 4].tag = true; else karno[2, 4].tag = false; } break;
                case 6: { karno[1, 3].value = val; if (val == 1) karno[1, 3].tag = true; else karno[1, 3].tag = false; } break;
                case 7: { karno[2, 3].value = val; if (val == 1) karno[2, 3].tag = true; else karno[2, 3].tag = false; } break;
            }
        }
        private bool isSel(byte c1, byte c2,byte c3 , byte c4)
        {
            if (getCellTag(c1) && getCellTag(c2) && getCellTag(c3) && getCellTag(c4)) return true; else return false;
        }
        private bool isSel(byte c1, byte c2)
        {
            if (getCellTag(c1) && getCellTag(c2)) return true; else return false; 
        }
        private bool isSel(byte c1)
        {
            if (getCellTag(c1)) return true; else return false;
        }
        #region States
        private bool isOne()
        {
            if (karno[1, 1].value == 1)
                if (karno[1, 2].value == 1)
                    if (karno[1, 3].value == 1)
                        if (karno[1, 4].value == 1)
                            if (karno[2, 1].value == 1)
                                if (karno[2, 2].value == 1)
                                    if (karno[2, 3].value == 1)
                                        if (karno[2, 4].value == 1)
                                        {                                            
                                            setCell(0, 1);
                                            setCell(1, 1);
                                            setCell(2, 1);
                                            setCell(3, 1);
                                            setCell(4, 1);
                                            setCell(5, 1);
                                            setCell(6, 1);
                                            setCell(7, 1);
                                            return true;
                                        }
            return false;
        }
        private bool isZero()
        {
            if (karno[1, 1].value == 0)
                if (karno[1, 2].value == 0)
                    if (karno[1, 3].value == 0)
                        if (karno[1, 4].value == 0)
                            if (karno[2, 1].value == 0)
                                if (karno[2, 2].value == 0)
                                    if (karno[2, 3].value == 0)
                                        if (karno[2, 4].value == 0)
                                        {                                            
                                            setCell(0, 0);
                                            setCell(1, 0);
                                            setCell(2, 0);
                                            setCell(3, 0);
                                            setCell(4, 0);
                                            setCell(5, 0);
                                            setCell(6, 0);
                                            setCell(7, 0);
                                            return true;
                                        }
            return false;
        }
        private bool isEnd()
        {
            //if (this.Count==8)
            //{
                for (byte x = 1; x <= 2; x++)
                    for (byte y = 1; y <= 4; y++)
                    {
                        if (karno[x, y].value ==1 && !karno[x, y].tag)  return false;
                    }
                return true;
           // }
        }
        #endregion
        public void Cell(byte index, byte val)
        {
            switch (index)
            {
                case 0: { karno[1, 1].value = val; karno[1, 1].tag = false; break; }
                case 1: { karno[2, 1].value = val; karno[2, 1].tag = false; break; }
                case 2: { karno[1, 2].value = val; karno[1, 2].tag = false; break; }
                case 3: { karno[2, 2].value = val; karno[2, 2].tag = false; break; }
                case 4: { karno[1, 4].value = val; karno[1, 4].tag = false; break; }
                case 5: { karno[2, 4].value = val; karno[2, 4].tag = false; break; }
                case 6: { karno[1, 3].value = val; karno[1, 3].tag = false; break; }
                case 7: { karno[2, 3].value = val; karno[2, 3].tag = false; break; }
            }
        }
        public string Optimized()
        {
            string str = "";
            string ch = "";
            #region Test
            if (isZero()) return "0";
            if (isOne()) return "1";
            while (!isEnd())
            {
                #region 4
                if (getCell(0) && getCell(1) && getCell(2) && getCell(3) && !isSel(0, 1, 2, 3))
                {
                    setCell(0, 1);
                    setCell(1, 1);
                    setCell(2, 1);
                    setCell(3, 1);
                    result[tedad] = "|A";
                    tedad++;
                    continue;
                }
                if (getCell(2) && getCell(3) && getCell(6) && getCell(7) && !isSel(2, 3, 6, 7))
                {
                    setCell(2, 1);
                    setCell(3, 1);
                    setCell(6, 1);
                    setCell(7, 1);
                    result[tedad] = "B";
                    tedad++;
                    continue;
                }
                if (getCell(4) && getCell(5) && getCell(6) && getCell(7) && !isSel(4, 5, 6, 7))
                {
                    setCell(4, 1);
                    setCell(5, 1);
                    setCell(6, 1);
                    setCell(7, 1);
                    result[tedad] = "A";
                    tedad++;
                    continue;
                }
                if (getCell(0) && getCell(2) && getCell(4) && getCell(6) && !isSel(0, 2, 4, 6))
                {
                    setCell(0, 1);
                    setCell(2, 1);
                    setCell(4, 1);
                    setCell(6, 1);
                    result[tedad] = "|C";
                    tedad++;
                    continue;
                }
                if (getCell(1) && getCell(3) && getCell(5) && getCell(7) && !isSel(1, 3, 5, 7))
                {
                    setCell(1, 1);
                    setCell(3, 1);
                    setCell(5, 1);
                    setCell(7, 1);
                    result[tedad] = "C";
                    tedad++;
                    continue;
                }
                if (getCell(0) && getCell(1) && getCell(4) && getCell(5) && !isSel(0, 1, 4, 5))
                {
                    setCell(0, 1);
                    setCell(1, 1);
                    setCell(4, 1);
                    setCell(5, 1);
                    result[tedad] = "|B";
                    tedad++;
                    continue;
                }
                #endregion
                #region 2
                if (getCell(0) && getCell(1) && !isSel(0, 1))
                {
                    setCell(0, 1);
                    setCell(1, 1);
                    result[tedad] = "|A|B";
                    tedad++;
                    continue;
                }
                if (getCell(2) && getCell(3) && !isSel(2, 3))
                {
                    setCell(2, 1);
                    setCell(3, 1);
                    result[tedad] = "|AB";
                    tedad++;
                    continue;
                }
                if (getCell(6) && getCell(7) && !isSel(6, 7))
                {
                    setCell(6, 1);
                    setCell(7, 1);
                    result[tedad] = "AB";
                    tedad++;
                    continue;
                }
                if (getCell(4) && getCell(5) && !isSel(4, 5))
                {
                    setCell(4, 1);
                    setCell(5, 1);
                    result[tedad] = "A|B";
                    tedad++;
                    continue;
                }
                if (getCell(0) && getCell(2) && !isSel(0, 2))
                {
                    setCell(0, 1);
                    setCell(2, 1);
                    result[tedad] = "|A|C";
                    tedad++;
                    continue;
                }
                if (getCell(4) && getCell(6) && !isSel(4, 6))
                {
                    setCell(4, 1);
                    setCell(6, 1);
                    result[tedad] = "A|C";
                    tedad++;
                    continue;
                }
                if (getCell(1) && getCell(3) && !isSel(1, 3))
                {
                    setCell(1, 1);
                    setCell(3, 1);
                    result[tedad] = "|AC";
                    tedad++;
                    continue;
                }
                if (getCell(5) && getCell(7) && !isSel(5, 7))
                {
                    setCell(5, 1);
                    setCell(7, 1);
                    result[tedad] = "AC";
                    tedad++;
                    continue;
                }
                if (getCell(0) && getCell(4) && !isSel(0, 4))
                {
                    setCell(0, 1);
                    setCell(4, 1);
                    result[tedad] = "|B|C";
                    tedad++;
                    continue;
                }
                if (getCell(1) && getCell(5) && !isSel(1, 5))
                {
                    setCell(1, 1);
                    setCell(5, 1);
                    result[tedad] = "|BC";
                    tedad++;
                    continue;
                }
                if (getCell(2) && getCell(6) && !isSel(2, 6))
                {
                    setCell(2, 1);
                    setCell(6, 1);
                    result[tedad] = "B|C";
                    tedad++;
                    continue;
                }
                if (getCell(3) && getCell(7) && !isSel(3, 7))
                {
                    setCell(3, 1);
                    setCell(7, 1);
                    result[tedad] = "BC";
                    tedad++;
                    continue;
                }
                #endregion
                #region 1
                if (getCell(0) && !isSel(0))
                {
                    setCell(0, 1);
                    result[tedad] = "|A|B|C";
                    tedad++;
                    continue;
                }
                if (getCell(1) && !isSel(1))
                {
                    setCell(1, 1);
                    result[tedad] = "|A|BC";
                    tedad++;
                    continue;
                }
                if (getCell(2) && !isSel(2))
                {
                    setCell(2, 1);
                    result[tedad] = "|AB|C";
                    tedad++;
                    continue;
                }
                if (getCell(3) && !isSel(3))
                {
                    setCell(3, 1);
                    result[tedad] = "|ABC";
                    tedad++;
                    continue;
                }
                if (getCell(4) && !isSel(4))
                {
                    setCell(4, 1);
                    result[tedad] = "A|B|C";
                    tedad++;
                    continue;
                }
                if (getCell(5) && !isSel(5))
                {
                    setCell(5, 1);
                    result[tedad] = "A|BC";
                    tedad++;
                    continue;
                }
                if (getCell(6) && !isSel(6))
                {
                    setCell(6, 1);
                    result[tedad] = "AB|C";
                    tedad++;
                    continue;
                }
                if (getCell(7) && !isSel(7))
                {
                    setCell(7, 1);
                    result[tedad] = "ABC";
                    tedad++;
                    continue;
                }
                #endregion
            }
            #endregion
            for (int i = 0; i < tedad; i++)
            {
                str += ch + result[i].ToString();
                ch = "+";
            }
            return str;
        }
        public Karno(byte count)
        {
            Count = count;
            tedad = 0;            
            if (count == 8)
            {
                result = new string[8];
                karno = new kcell[3, 5];   // kcell[2,4]!!!!
                for (byte x = 1; x <= 2; x++)
                    for (byte y = 1; y <= 4; y++)
                    {
                        karno[x, y].value = 0;
                        karno[x, y].tag = false;
                    }
            }
            /*else if (count == 16)
            {
                karno = new kcell[3, 3];
            }*/
        }        
    }
}
